//
// Created by 成飞 on 2024/1/4.
//

#ifndef ORDERKV_CONF_PARSER_HPP
#define ORDERKV_CONF_PARSER_HPP

#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>
#include <cassert>

#include "default_conf_info.h"

namespace conf {

class Section {
    std::string section;
    std::map<std::string, std::string> mapValue;

public:
    explicit Section(std::string &section) {
        this->section = section;
    }

    void add_key_value(const std::string& key, const std::string& value) {
        std::pair<std::string, std::string> p(key, value);
        mapValue.insert(p);
    }

    void add_key_value(std::map<std::string,std::string> m){
        mapValue.insert(m.begin(), m.end());
    }

    void set_key_value(const std::string &key, const std::string& value){
        mapValue.insert_or_assign(key, value);
    }

    void set_key_value(const std::map<std::string, std::string>& m){
        for (const auto& pair : m) {
            mapValue.insert_or_assign(pair.first, pair.second);
        }
    }

    std::string* get_value(const std::string& key) {
        auto it = mapValue.find(key);
        if (it == mapValue.end()){
            return nullptr;
        }
        return &(*it).second;
    }

    void show(std::ostream &os) {
        os << '[' << section << ']' << std::endl;
        for_each(mapValue.begin(), mapValue.end(), [&os](const std::pair<std::string, std::string> &p) {
            os << "\t" << p.first << " = " << p.second << std::endl;
        });
    }
};

class SectionCollect {
    std::map<std::string, Section> mapSection;

public:
    Section* add_section(std::string strSection) {
        std::pair<std::string, Section> p(strSection, Section(strSection));
        mapSection.insert(p);
        return get_section(strSection);
    }

    Section *get_section(const std::string &strSection) {
        auto it = mapSection.find(strSection);
        if(it == mapSection.end()) return nullptr;
        return &((*it).second);
    }

    Section *get_section_if_null_add(const std::string &strSection){
        Section *pSection = get_section(strSection);
        if (pSection == nullptr){
            pSection = add_section(strSection);
        }
        return pSection;
    }

    void show(std::ostream &os) {
        auto it = mapSection.begin();
        while (it != mapSection.end()) {
            ((*it).second).show(os);
            it++;
        }
    }
};

class ConfReadParser {
    std::string strPath;
    SectionCollect &collect;
public:
    ConfReadParser(std::string strPath, SectionCollect &collect) : strPath(std::move(strPath)), collect(collect) {}

    static void trim(std::string &s) {
        if (!s.empty()) {        //find_first_not_of返回下标位置
            s.erase(0, s.find_first_not_of(' '));    //删除左空格
            if (!s.empty()) {
                s.erase(s.find_last_not_of(' ') + 1);    //删除右空格
            }
        }
    }

    static std::string parse_section(std::string &strText) {
        strText.erase(0, strText.find_first_not_of('['));
        strText.erase(strText.find_last_not_of(']') + 1);
        return strText;
    }

    static void parse_pair(const std::string &strText, std::string &key, std::string &value) {
        unsigned int pos = strText.find('=');
        key = strText.substr(0, pos);
        value = strText.substr(pos + 1, strText.length() - pos - 1);
        trim(key);
        trim(value);
    }

    void Process() {
        std::string strLine;
        std::string strSection;
        std::string strKey;
        std::string strValue;

        Section *pSection = nullptr;
        std::ifstream in(strPath.c_str());
        while (!in.eof()) {
            getline(in, strLine);
            trim(strLine);
            if (strLine.empty() || strLine[0] == ';')continue;
            if (strLine[0] == '[') {
                strSection = parse_section(strLine);
                pSection = collect.get_section_if_null_add(strSection);//获取当前对象的key-value键值对
            } else {
                parse_pair(strLine, strKey, strValue);
                assert(pSection != nullptr || assert_msg("null section, please check the format of orderkv.conf"));
                pSection->add_key_value(strKey, strValue);
            }
        }
        in.close();
    }
};

}

#endif //ORDERKV_CONF_PARSER_HPP
